//!
//! 提供内存池管理机制, 支持从堆上动态分配，或者事先分配的一块内存空间，可能在堆上也可能在栈上.
//!
//! # Examples
//!
//! 简单类型，直接传递初始值，会有一次拷贝
//! ```rust
//! use hipool::{ MemPool, Boxed};
//! let pool = MemPool::new(0);
//! let psize = Boxed::new_in(&pool, 100).unwrap();
//! assert_eq!(*psize, 100);
//! ```
//!
//! 复杂类型，避免拷贝的一种方式:
//! ```rust
//! use core::ptr;
//! use hipool::{ MemPool, Boxed};
//! use core::mem::MaybeUninit;
//!
//! let pool = MemPool::new(0);
//! struct Foo {
//!     val: i32,
//! }
//! let foo = Boxed::new_then_in(&pool, | obj: &mut MaybeUninit<Foo> | {
//!     let obj = obj.as_mut_ptr();
//!     unsafe {
//!         ptr::addr_of_mut!((*obj).val).write(100);
//!     }
//!     Ok(())
//! }).unwrap();
//! assert_eq!(foo.val, 100);
//! ```
//!
//! 有时候需要在栈上分配数据，需要把栈空间适配为Pool接口，则可使用BufPool完成适配
//!
//! ```rust
//! use hipool::{ BufPool, Boxed};
//! let mut buf = [0_u8; 100];
//! let mut pool = BufPool::new(&mut buf);
//! let psize = Boxed::new_in(&pool, 100).unwrap();
//! assert_eq!(*psize, 100);
//! ```
//!
//! 有时候分配的Pool也需要在堆上，可以用另外的构造方式，如下:
//!
//! ```rust
//! use hipool::{ MemPool, Boxed };
//! use core::mem::MaybeUninit;
//!
//! let mut pool = MemPool::new_boxed(0).unwrap();
//! let int_array = Boxed::new_slice_then_in(&*pool, 100, |_, ele: &mut MaybeUninit<i32>| {
//!     ele.write(0);
//!     Ok(())
//! }).unwrap();
//! int_array.iter().for_each(|n| assert_eq!(*n, 0));
//! ```
//!
//! 更多的调用接口
//!
//! ```rust
//! use hipool::{ MemPool, Boxed };
//! use core::mem::MaybeUninit;
//! use core::alloc::Layout;
//!
//! let pool = MemPool::new_boxed(0).unwrap();
//!
//! let val = Boxed::new_in(&*pool, 1).unwrap();
//! assert_eq!(*val, 1);
//!
//! let val = Boxed::new_in(&*pool, 0).unwrap();
//! assert_eq!(*val, 0);
//!
//! let val = Boxed::new_then_in(&*pool, |val: &mut MaybeUninit<i32>| {
//!     val.write(100);
//!     Ok(())
//! }).unwrap();
//! assert_eq!(*val, 100);
//!
//! let ivals = [0, 1, 2, 3];
//! let vals = Boxed::uninit_slice_in::<i32>(&*pool, ivals.len()).unwrap();
//! let vals = vals.write_slice_then(|n, uninit| {uninit.write(ivals[n]); Ok(())}).unwrap();
//! assert_eq!(vals[0], 0);
//! assert_eq!(vals[1], 1);
//! assert_eq!(vals[2], 2);
//! assert_eq!(vals[3], 3);
//!
//! let vals = unsafe { Boxed::new_buf_in(&*pool,
//! Layout::array::<i32>(2).unwrap()).unwrap().cast_slice::<i32>(2) };
//! vals.iter().for_each(|val| println!(" {:?} ", val));
//!
//! let vals = Boxed::new_slice_then_in(&*pool, 2, | n, val: &mut MaybeUninit<i32> | {
//!     val.write(n as i32);
//!     Ok(())
//! }).unwrap();
//! assert_eq!(vals[0], 0);
//! assert_eq!(vals[1], 1);
//! ```
//!

#![no_std]

pub use hierr::{Error, prelude};

mod boxed;
mod buf;
mod mem;
pub(crate) mod util;

mod alloc;
pub use crate::boxed::Boxed;
pub use crate::buf::Pool as BufPool;
pub use crate::buf::BoxedPool as BoxedBufPool;
pub use crate::mem::Pool as MemPool;
pub use crate::mem::BoxedPool as BoxedMemPool;
pub use alloc::*;

mod rc;
pub use rc::*;
mod arc;
pub use arc::*;


#[cfg(test)]
mod test {
    use crate::{Boxed, BufPool, MemPool};

    struct Foo {
        val: usize,
    }

    static mut DROP_CNT: usize = 0;

    impl Drop for Foo {
        fn drop(&mut self) {
            unsafe { DROP_CNT += self.val };
        }
    }

    #[test]
    fn test_mem_drop() {
        let pool = MemPool::new(0);
        unsafe {
            DROP_CNT = 0;
        }

        {
            let _ = Boxed::new_in(&pool, Foo { val: 100 });
        }

        unsafe {
            assert_eq!(100, DROP_CNT);
        }
    }
    #[test]
    fn test_buf_drop() {
        let mut buf = [0_u8; 100];
        let pool = BufPool::new(&mut buf);
        unsafe {
            DROP_CNT = 0;
        }

        {
            let _ = Boxed::new_in(&pool, Foo { val: 100 });
        }

        unsafe {
            assert_eq!(100, DROP_CNT);
        }
    }

    #[test]
    fn test_static() {
        let pool = MemPool::new_boxed(0).unwrap();
        let pool = pool.leak();
        let x: Boxed<'static, i32, &'static MemPool> = Boxed::new_in(&*pool, 100).unwrap();
        assert_eq!(*x, 100);
    }
}
